package cn.bigcontainer.alt.workflow.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import cn.bigcontainer.alt.meta.service.MDictionaryService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import cn.bigcontainer.alt.common.util.WoKit;
import cn.bigcontainer.alt.meta.dto.MAppDto;
import cn.bigcontainer.alt.meta.dto.MCrud;
import cn.bigcontainer.alt.meta.dto.MObjectDto;
import cn.bigcontainer.alt.meta.dto.MViewDto;
import cn.bigcontainer.alt.meta.exception.MException;
import cn.bigcontainer.alt.meta.mapper.MAppMapper;
import cn.bigcontainer.alt.meta.mapper.MViewMapper;
import cn.bigcontainer.alt.meta.po.MApp;
import cn.bigcontainer.alt.meta.po.MObject;
import cn.bigcontainer.alt.meta.po.MView;
import cn.bigcontainer.alt.meta.po.MViewProperty;
import cn.bigcontainer.alt.meta.service.MetaService;
import cn.bigcontainer.alt.meta.util.MConstant;
import cn.bigcontainer.alt.workflow.mapper.MTaskDefinitionMapper;
import cn.bigcontainer.alt.workflow.po.MTaskDefinition;
import cn.bigcontainer.alt.workflow.service.MWorkflowMetaService;
import cn.bigcontainer.alt.workflow.util.WorkflowUtil;
import lombok.extern.slf4j.Slf4j;

@Service
@Transactional
@Slf4j
public class MWorkflowMetaServiceImpl implements MWorkflowMetaService {

    @Resource
    private MetaService metaService;

    private final static String REG_TASK = "([^\\s;]+[\"][^\\s\"]+[\"][^\\s;]+|[^\\s;]+)[;]?";

    private Map<String, String> parseTask (String taskData) {
        Map<String, String> map = new HashMap<>();
        // 解析任务属性值
        Matcher matcher = Pattern.compile(MConstant.REG_KEY_VALUE2 + "|" + MConstant.REG_KEY_VALUE).matcher(taskData);
        while (matcher.find()) {
            String key = matcher.group(1);
            String value = matcher.group(2);
            if (key == null) {
                key = matcher.group(3);
                value = matcher.group(4);
            }
            map.put(key, value);
        }
        // 设置任务名称
        int i = taskData.indexOf('(');
        if (i > 0) {
            map.put("name", taskData.substring(0, i));
        } else {
            map.put("name", taskData);
        }
        // 设置审批
        if (map.get("审批") == null) {
            if (map.get("name").indexOf("审批") > -1 || map.get("name").indexOf("审核") > -1) {
                map.put("审批", "是");
            } else {
                map.put("审批", "否");
            }
        }
        // 设置默认属性
        String name = map.get("name");
        String defaultProps = null;
        if ("是".equals(map.get("审批"))) {
            defaultProps = WorkflowUtil.getReviewProperties(name);
        } else {
            defaultProps = WorkflowUtil.getDefaultProperties(name);
        }
        String props = map.get("属性");
        if (props == null) {
            props = defaultProps;
        } else {
            props += ";" + defaultProps;
        }
        map.put("属性", props);
        return map;
    }

    @Resource
    private MAppMapper appMapper;

    @Resource
    private MViewMapper viewMapper;

    private final static String REG_PROP_NAME = "关联:([^\\s,()]+)";

    private MView createTaskView (int index, Map<String, String> task, MObject object, MView view) {
        MView taskView = metaService.cloneView(view);
        taskView.setName(task.get("name"));
        taskView.getProperties().clear();
        // 获取对象主键属性id
        String keyIds = MObjectDto.getKeyIds(object);
        // task中是否有主键，如果没有，需要加上
        Boolean key = false;
        //
        String[] props = task.get("属性").split(";");
        for (String prop : props) {
            int idx = prop.indexOf("(");
            final String name;
            if (idx == -1) {
                if (prop.indexOf("关联:") == -1) {
                    name = prop;
                } else {
                    Matcher matcher = Pattern.compile(REG_PROP_NAME).matcher(prop);
                    if (matcher.find()) {
                        name = matcher.group(1);
                    } else {
                        throw new MException(MException.PROP_FORMAT);
                    }
                }
            } else {
                name = prop.substring(0, idx);
            }
            Optional<MViewProperty> viewPropertyOptional = view.getProperties().stream().filter(v -> v.getName().equals(name)).findFirst();
            if (viewPropertyOptional.isPresent()) {
                // 克隆视图属性
                MViewProperty cloneBySetter = WoKit.cloneBySetter(viewPropertyOptional.get(), MViewProperty.class);
                // 修改视图属性id
                String s = metaService.copyViewPropertyOrButtonId(cloneBySetter.getId(), view.getId(), taskView.getId());
                cloneBySetter.setId(s);
                // 任务视图添加视图属性
                taskView.getProperties().add(cloneBySetter);
                if (keyIds.equals(cloneBySetter.getPropertyId())) {
                    key = true;
                }
            }
        }
        if (!key) {
            MViewProperty keyViewProperty = view.getProperties().stream().filter(vp -> keyIds.equals(vp.getPropertyId())).findFirst().get();
            String id = metaService.copyViewPropertyOrButtonId(keyViewProperty.getId(), view.getId(), taskView.getId());
            keyViewProperty.setId(id);
            keyViewProperty.setType(MViewProperty.TYPE_HIDDEN);
            taskView.getProperties().add(0, keyViewProperty);
        }
        return taskView;
    }

    @Resource
    private MTaskDefinitionMapper taskDefinitionMapper;

    @Resource
    private MDictionaryService dictionaryService;

    public void deleteMeta (String appId) {
        // 删除MTaskDefinition
        taskDefinitionMapper.delete(new QueryWrapper<MTaskDefinition>().eq("process_definition_id", appId));
        MApp app = appMapper.selectById(appId);
        if (app == null) {
            log.warn("MApp(id={})不存在", appId);
            return;
        }
        // 删除视图
        for (String key : app.getData().keySet()) {
            if (key.startsWith(MAppDto.PREFIX_VIEW)) {
                String viewId = app.getData().getString(key);
                viewMapper.deleteById(viewId);
            }
        }
        // 删除应用
        appMapper.deleteById(appId);
    }

    /**
     *
     * @param module 工作流所属的模块
     * @param name 工作流中英文名称
     * @param tasks 流程任务描述，以双分号隔开；格式如方括号中的内容所示：
     *              [申请(属性:"propsDesc",审批:否,并行:否);部门审批;公司审批]；任务描述中的符号仅支持英文(:/",()),
     *              propsDesc格式请参考cn.bigcontainer.alt.meta.service.MetaService#createMeta的第三个参数。
     * @return
     */
    @Override
    public MObject createMeta(String module, String name, String tasks) {
        Matcher matcher = Pattern.compile(REG_TASK).matcher(tasks);
        List<Map<String, String>> taskList = new ArrayList<>();
        String props = "";
        while (matcher.find()) {
            for (int i = 0; i < matcher.groupCount(); i ++) {
                String task = matcher.group(i + 1);
                Map<String, String> parseTask = parseTask(task);
                taskList.add(parseTask);
                if (!props.equals("")) {
                    props += ";";
                }
                props += parseTask.get("属性");
            }
        }
        // 没有主键则添加
        if (props.indexOf("主键:是") < 0) {
            props = MConstant.PROP_KEY + ";" + props;
        }
        props += String.format(";修改时间(类型:日期时间,默认值:%s)", MConstant.DEFAULT_UPDATE_TIME);
        props += ";任务ID(类型:文本,长度:200)";
        props += ";审批状态(类型:文本,长度:10)";
        MObject object = metaService.createMeta(module, name, props);
        // 获取默认crud，以其视图作为模板
        MApp app = appMapper.selectOne(new QueryWrapper<MApp>().eq("object_id", object.getId()).eq("status", 2));
        // 创建视图
        MView create = viewMapper.selectById(app.getData().getString(MCrud.PARAM_CREATE));
        MView update = viewMapper.selectById(app.getData().getString(MCrud.PARAM_UPDATE));
        update.getProperties().stream().forEach(vp -> {
            for (Map<String, String> task : taskList) {
                if ("是".equals(task.get("审批")) && vp.getName().equals(task.get("name") + "结果")) {
                    vp.getData().put(MObjectDto.PARAM_URL, "meta/form/props/review");
                    vp.setType(null);
                }
            }
        });
        MView list = viewMapper.selectById(app.getData().getString(MCrud.PARAM_LIST));
        MView search = viewMapper.selectById(app.getData().getString(MCrud.PARAM_SEARCH));
        // 删除应用
        String workflowId = "workflowx_" + object.getId();
        this.deleteMeta(workflowId);
        // 构造工作流应用
        MApp workflow = new MApp();
        workflow.setId(workflowId);
        workflow.setIdx(0);
        workflow.setStatus(2);// 2表示默认
        workflow.setName(name);
        workflow.setObjectId(object.getId());
        workflow.setTemplate("meta/workflow");
        workflow.setType(MAppDto.TYPE_WORKFLOW);
        // 复制列表视图
        MView wfList = metaService.cloneView(list);
        // - 设置“任务ID”属性
        MViewProperty rwid = MViewDto.getPropertyBySuffix(wfList, "mrwid");
        rwid.setType(MViewProperty.TYPE_DICTIONARY);
        rwid.setDictionaryType(module + "." + object.getNo() + ".task");// 数据字典创建请看：插入“任务”数据字典
        rwid.setWidth(100);
        // - 设置“审批状态”属性
        MViewProperty spzt = MViewDto.getPropertyBySuffix(wfList, "mspzt");
        spzt.setType(MViewProperty.TYPE_DICTIONARY);
        spzt.setDictionaryType("wf.reviewstatus");// 具体值参考：adminlte-platform/src/main/resources/db/data-workflow.sql
        spzt.setWidth(100);
        // - 隐藏主键属性
        MViewDto.getKeyProperties(object, wfList).get(0).setType(MViewProperty.TYPE_HIDDEN);
        wfList.getButtons().get(2).setName("处理");
        viewMapper.insert(wfList);
        workflow.getData().put(MCrud.PARAM_LIST, wfList.getId());
        // 复制创建视图
        MView wfCreate = createTaskView(0, taskList.get(0), object, create);
        viewMapper.insert(wfCreate);
        workflow.getData().put(MCrud.PARAM_CREATE, wfCreate.getId());
        // 复制列表视图
        MView wfSearch = metaService.cloneView(search);
        viewMapper.insert(wfSearch);
        workflow.getData().put(MCrud.PARAM_SEARCH, wfSearch.getId());
        // 任务定义
        // - 任务数据字典数据
        Map<String, String> dictinaryData = new HashMap<>();
        dictinaryData.put("-1", "结束");
        for (int i = 0; i < taskList.size(); i ++) {
            Map<String, String> task = taskList.get(i);
            MTaskDefinition taskDefinition = new MTaskDefinition();
            taskDefinition.setId(workflow.getId() + "_" + i);
            taskDefinition.setIdx(i);
            taskDefinition.setProcessDefinitionId(workflow.getId());
            taskDefinition.setReview("是".equals(task.get("审批")) ? 1 : 0);
            taskDefinition.setTaskExpression(null);
            taskDefinition.setTaskCandidateExpression(null);
            // 创建MTaskDefinition对应的视图
            MView taskView = createTaskView(i, task, object, update);
            workflow.getData().put(MAppDto.PREFIX_VIEW + taskDefinition.getId(), taskView.getId());
            viewMapper.insert(taskView);
            taskDefinition.setFormViewId(taskView.getId());
            taskDefinitionMapper.insert(taskDefinition);
            // 设置任务数据字典数据
            dictinaryData.put(taskDefinition.getId(), taskView.getName());
        }
        // 插入“任务”数据字典
        dictionaryService.createOrReplaceDictionaries(dictinaryData, rwid.getDictionaryType(), name + "任务");
        appMapper.insert(workflow);
        return object;
    }

    public static void main(String[] args) {
        Matcher matcher = Pattern.compile(MConstant.REG_KEY_VALUE2 + "|" + MConstant.REG_KEY_VALUE).matcher("申请(属性:\"ID;姓名(长度:100,范围:1/200)\",审批:否,并行:否)");
        while (matcher.find()) {
            log.info("---------");
            for (int i = 0; i < matcher.groupCount(); i ++) {
                log.info(matcher.group(i + 1));
            }
        }
    }
}
